package com.markix.configuration;

import com.markix.dao.UserToAuthDao;
import com.markix.security.FormLoginAuthenticationSuccessHandler;
import com.markix.security.UserDetailsServiceImpl;
import com.markix.security.oauth2login.OAuth2LoginAuthenticationFailureHandler;
import com.markix.security.oauth2login.OAuth2LoginAuthenticationSuccessHandler;
import com.markix.security.oauth2login.TempAuthFilter;
import com.markix.security.oauth2login.WebAttributes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter;
import org.springframework.security.web.authentication.NullRememberMeServices;
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;

/**
 * @author markix
 */
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        return new UserDetailsServiceImpl();
    }

    @Autowired
    private UserToAuthDao userToAuthDao;
    @Autowired
    private ClientRegistrationRepository clientRegistrationRepository;

    @Override
    public void configure(WebSecurity web) throws Exception {
        web
                //忽略权限验证
                .ignoring()
                // 静态资源 css/js/images
                .requestMatchers(PathRequest.toStaticResources().atCommonLocations())
                .antMatchers("/error")
                .antMatchers("/oauth-types", "/curr-oauth"
                        , WebAttributes.loginPage
                        , WebAttributes.bindPage
                )
        ;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                // 支持自己系统的用户登录
                .formLogin()
                .loginProcessingUrl(WebAttributes.loginApi)
                .loginPage(WebAttributes.loginPage)
                .successHandler(new FormLoginAuthenticationSuccessHandler(userToAuthDao))
                .and()

                // 用于暂存用户认证信息，辅助完成 三方帐号登录和绑定流程
                .addFilterBefore(new TempAuthFilter(), OAuth2LoginAuthenticationFilter.class)

                // 支持三方帐号登录
                .oauth2Login()
                .withObjectPostProcessor(new ObjectPostProcessor<OAuth2LoginAuthenticationFilter>() {
                    @Override
                    public <O extends OAuth2LoginAuthenticationFilter> O postProcess(O object) {
                        object.setSessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy());
                        object.setRememberMeServices(new NullRememberMeServices());
                        return object;
                    }
                })
                .successHandler(new OAuth2LoginAuthenticationSuccessHandler(userToAuthDao, userDetailsService(), clientRegistrationRepository))
                .failureHandler(new OAuth2LoginAuthenticationFailureHandler())
                .and()

                .rememberMe()
                .and()

                .csrf().disable()
        ;
    }




}
